﻿using System;
using System.Collections.Generic;
using System.Linq;

using NHibernate;
using System.Threading;
using System.Runtime.CompilerServices;
using System.Data;

namespace Laugh.Data.DatabaseCfg
{
    public class SessionFactoryHolder : ISessionFactoryHolder
    {
        public static readonly string DefaultKey = "default.database.sessionfactorykey";

        private readonly IDictionary<string, ISessionFactory> _sessionFactories = new Dictionary<string, ISessionFactory>();
        private readonly IDictionary<ISessionFactory, IInterceptor> _sessionInterceptors = new Dictionary<ISessionFactory, IInterceptor>();
        //private readonly IDictionary<Type, string> _sessionFactoryTypeCache = new Dictionary<Type, string>();
        //private readonly IDictionary<string, NHibernate.Cfg.Configuration> _configurations = new Dictionary<string, NHibernate.Cfg.Configuration>();
        private readonly ReaderWriterLock readerWriterLock = new ReaderWriterLock();

        #region ISessionFactoryHolder成员

        public ISessionFactory GetSessionFactory(string key = null)
        {
            key = key ?? DefaultKey;
            if (_sessionFactories.ContainsKey(key))
                return _sessionFactories[key];

            throw new DataException("没有注册当前数据库[{0}]".Format2(key));
        }

        public ISessionFactoryHolder Register(string key, ISessionFactory sessionFactory, NHibernate.Cfg.Configuration configuration, IInterceptor interceptor = null)
        {
            readerWriterLock.AcquireWriterLock(-1);

            string sfKey = key ?? DefaultKey;

            try
            {
                _sessionFactories[sfKey] = sessionFactory;
                //_configurations[sfKey] = configuration;

                if (interceptor != null)
                    _sessionInterceptors[sessionFactory] = interceptor;

                //var classMappings = sessionFactory.GetAllClassMetadata();

                //if (classMappings != null && classMappings.Count > 0)
                //classMappings.Each(map => _sessionFactoryTypeCache.Add(map.Value.GetMappedClass(EntityMode.Poco), key));
            }
            finally
            {
                readerWriterLock.ReleaseWriterLock();
            }
            return this;
        }

        public ISessionFactoryHolder RegisterDefault(ISessionFactory sessionFactory, NHibernate.Cfg.Configuration configuration, IInterceptor interceptor = null)
        {
            return Register(DefaultKey, sessionFactory, configuration, interceptor);
        }

        [MethodImpl(MethodImplOptions.Synchronized)]
        public ISession OpenSession(ISessionFactory sessionFactory)
        {
            ISession session = OpenSession(sessionFactory, GetInterceptor(sessionFactory));

            return session;
        }

        public List<ISessionFactory> SessionFactories
        {
            get { return _sessionFactories.Values.ToList(); }
        }

        //public NHibernate.Cfg.Configuration GetConfiguration(string key = null)
        //{
        //    key = key ?? DefaultKey;
        //    return _configurations[key];
        //}

        #endregion

        private IInterceptor GetInterceptor(ISessionFactory sessionFactory)
        {
            IInterceptor interceptor = null;

            if (_sessionInterceptors.TryGetValue(sessionFactory, out interceptor))
            {
                return interceptor;
            }
            return null;
        }

        private static ISession OpenSession(ISessionFactory sessionFactory, IInterceptor interceptor = null)
        {
            lock (sessionFactory)
            {
                ISession session;
                if (interceptor == null)
                    session = sessionFactory.OpenSession();
                else
                {
                    session = sessionFactory.OpenSession(interceptor);

                }
                session.BeginTransaction();

                return session;
            }
        }
    }
}
